﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mbs.Collections;
using System.Threading;

namespace Mbs.Threading
{
  
    public interface IActiveObject:IStartable,IDisposable
    {
        void AddCommand(ICommand cmd);
        uint Interval { get; set; }
    }

    public abstract class ActiveCommand : ICommand
    {
        public static ICommand Current { get; internal set; }
        public abstract void Execute();
    }

    class DelegateComand : ActiveCommand
    {
        private Action InnerCommand;
        public DelegateComand(Action command)
        {
            InnerCommand = command;
        }

        public override void Execute()
        {
            if (InnerCommand != null)
                InnerCommand();
        }
    }

    public static class ActiveObjectExtensions
    {
        public static void AddCommand(this IActiveObject activeObject, Action command)
        {
            activeObject.AddCommand(new DelegateComand(command));
        }
    }

    public class ActiveObject : DisposableObject, IActiveObject
    {
        private uint _Interval = 100;

        public ActiveObject()
        {
            ActiveQueue = new SyncQueue<ICommand>();
            Name = "Active Object";
        }


        public void AddCommand(ICommand cmd)
        {
            if (cmd == null)
                throw new ArgumentNullException("cmd");


            ActiveQueue.Enqueue(cmd);
        }


        private IQueue<ICommand> ActiveQueue;
        private Timer timer;

        public string Name { get; protected set; }

        public uint Interval
        {
            get { return _Interval; }
            set
            {
                if (value != _Interval)
                {
                    _Interval = value;
                    if (timer != null)
                        timer.Change(0, _Interval);
                }
                    
            }
        }

        public void Start()
        {
            if (timer != null)
                throw new InvalidOperationException("Active object has already started.");
            timer = new Timer(state => Run(), null, 50, Interval);
        }

        private void Run()
        {
            var item = ActiveQueue.Dequeue();

            ActiveCommand.Current = item;
            if (item != null)
            {
                try
                {
                    item.Execute();
                }
                catch (Exception ex)
                {
                }
            }
        }


        public void Stop()
        {
            try
            {
                timer.Dispose();

            }
            finally
            {
                timer = null;
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                Stop();
                try
                {
                    ActiveQueue.Dispose();
                }
                finally
                {
                }
            }
        }

    }
}
